<template>
  <e-select
    ref="select"
    class="haloe-auto-complete"
    :label="label"
    :disabled="itemDisabled"
    :clearable="clearable"
    :placeholder="placeholder"
    :size="size"
    :placement="placement"
    :model-value="currentValue"
    :transfer-class-name="transferClassName"
    filterable
    remote
    auto-complete
    :remote-method="remoteMethod"
    @on-select="handleSelect"
    @on-clickoutside="handleClickOutside"
    :transfer="transfer"
    :capture="capture"
    :eventsEnabled="eventsEnabled"
  >
    <template #input>
      <slot name="input">
        <e-input
          :element-id="elementId"
          ref="input"
          v-model="currentValue"
          :name="name"
          :placeholder="placeholder"
          :disabled="itemDisabled"
          :size="size"
          :icon="inputIcon"
          @on-click="handleClear"
          @on-focus="handleFocus"
          @on-blur="handleBlur"
        ></e-input>
      </slot>
    </template>
    <slot>
      <e-option v-for="item in filteredData" :value="item" :key="item">{{
        item
      }}</e-option>
    </slot>
  </e-select>
</template>
<script>
import { getCurrentInstance, nextTick } from 'vue'
import eSelect from '../select/select.vue'
import eOption from '../select/option.vue'
import eInput from '../input/input.vue'
import { oneOf } from '../../utils/assist'
import mixinsForm from '../../mixins/form'

export default {
  name: 'AutoComplete',
  mixins: [mixinsForm],
  components: { eSelect, eOption, eInput },
  emits: [
    'update:modelValue',
    'on-change',
    'on-search',
    'on-select',
    'on-focus',
    'on-blur',
    'on-clear',
  ],
  props: {
    modelValue: {
      type: [String, Number],
      default: '',
    },
    label: {
      type: [String, Number],
      default: '',
    },
    data: {
      type: Array,
      default: () => [],
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    clearable: {
      type: Boolean,
      default: false,
    },
    placeholder: {
      type: String,
    },
    size: {
      validator(value) {
        return oneOf(value, ['small', 'large', 'default'])
      },
      default() {
        const global = getCurrentInstance().appContext.config.globalProperties
        return !global.$HALOE || global.$HALOE.size === ''
          ? 'default'
          : global.$HALOE.size
      },
    },
    icon: {
      type: String,
    },
    filterMethod: {
      type: [Function, Boolean],
      default: false,
    },
    placement: {
      validator(value) {
        return oneOf(value, [
          'top',
          'bottom',
          'top-start',
          'bottom-start',
          'top-end',
          'bottom-end',
        ])
      },
      default: 'bottom-start',
    },
    transfer: {
      type: Boolean,
      default() {
        const global = getCurrentInstance().appContext.config.globalProperties
        return !global.$HALOE || global.$HALOE.transfer === ''
          ? false
          : global.$HALOE.transfer
      },
    },
    name: {
      type: String,
    },
    elementId: {
      type: String,
    },
    transferClassName: {
      type: String,
    },
    // 4.6.0
    capture: {
      type: Boolean,
      default() {
        const global = getCurrentInstance().appContext.config.globalProperties
        return !global.$HALOE ? true : global.$HALOE.capture
      },
    },
    // 4.6.0
    eventsEnabled: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      currentValue: this.modelValue,
      disableEmitChange: false, // for Form reset
    }
  },
  computed: {
    inputIcon() {
      let icon = ''
      if (this.clearable && this.currentValue && !this.disabled) {
        icon = 'close'
      } else if (this.icon) {
        icon = this.icon
      }
      return icon
    },
    filteredData() {
      if (this.filterMethod) {
        return this.data.filter((item) =>
          this.filterMethod(this.currentValue, item)
        )
      } else {
        return this.data
      }
    },
  },
  watch: {
    modelValue(val) {
      if (this.currentValue !== val) {
        this.disableEmitChange = true
      }
      this.currentValue = val
    },
    currentValue(val) {
      this.$refs.select.setQuery(val)
      this.$emit('update:modelValue', val)
      if (this.disableEmitChange) {
        this.disableEmitChange = false
        return
      }
      this.$emit('on-change', val)
      this.handleFormItemChange('change', val)
    },
  },
  methods: {
    remoteMethod(query) {
      this.$emit('on-search', query)
    },
    handleSelect(option) {
      const val = option.value
      if (val === undefined || val === null) return
      this.currentValue = val
      this.$refs.input.blur()
      this.$emit('on-select', val)
    },
    handleFocus(event) {
      this.$emit('on-focus', event)
    },
    handleBlur(event) {
      this.$emit('on-blur', event)
    },
    handleClear() {
      if (!this.clearable) return
      this.currentValue = ''
      this.$refs.select.reset()
      this.$emit('on-clear')
    },
    handleClickOutside() {
      nextTick(() => {
        this.$refs.input.blur()
      })
    },
  },
}
</script>
